<html>
<head>
  <title>NPAPI ClearSiteData/GetSitesWithData Functionality</title>
  <script type="application/javascript" src="/MochiKit/packed.js"></script>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript" src="/tests/SimpleTest/PluginUtils.js"></script>
</head>
<body>
  <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>

  <script class="testbody" type="application/javascript">
    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
    SimpleTest.waitForExplicitFinish();

    const pluginHostIface = Components.interfaces.nsIPluginHost_MOZILLA_2_0_BRANCH;
    var pluginHost = Components.classes["@mozilla.org/plugin/host;1"].
                     getService(pluginHostIface);
    const FLAG_CLEAR_ALL = pluginHostIface.FLAG_CLEAR_ALL;
    const FLAG_CLEAR_CACHE = pluginHostIface.FLAG_CLEAR_CACHE;

    // Make sure clearing by timerange is supported.
    var p = document.getElementById("plugin1");
    p.setSitesWithDataCapabilities(true);

    ok(PluginUtils.withTestPlugin(runTest), "Test plugin found");

    function stored(needles) {
      var something = pluginHost.siteHasData(this.pluginTag, null);
      if (!needles)
        return something;

      if (!something)
        return false;

      for (var i = 0; i < needles.length; ++i) {
        if (!pluginHost.siteHasData(this.pluginTag, needles[i]))
          return false;
      }
      return true;
    }

    function checkThrows(fn, result) {
      try {
        fn();
        throw new Error("bad exception");
      } catch (e) {
        is(e.result, result, "Correct exception thrown");
      }
    }

    function runTest(pluginTag) {
      netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

      this.pluginTag = pluginTag;

      p.setSitesWithData(
        "foo.com:0:5," +
        "foo.com:0:7," +
        "bar.com:0:10," +
        "baz.com:0:10," +
        "foo.com:1:7," +
        "qux.com:1:5," +
        "quz.com:1:8"
      );

      ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
        "Data stored for sites");

      // Clear nothing.
      pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 4);
      ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
         "Data stored for sites");

      pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 4);
      ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
         "Data stored for sites");

      // Clear cache data 5 seconds or older.
      pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 5);
      ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
         "Data stored for sites");
      ok(!stored(["qux.com"]), "Data cleared for qux.com");

      // Clear cache data for foo.com, but leave non-cache data.
      pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_CACHE, 20);
      ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
         "Data stored for sites");

      // Clear all data 7 seconds or older.
      pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 7);
      ok(stored(["bar.com","baz.com","quz.com"]), "Data stored for sites");
      ok(!stored(["foo.com"]), "Data cleared for foo.com");
      ok(!stored(["qux.com"]), "Data cleared for qux.com");

      // Clear all cache data.
      pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20);
      ok(stored(["bar.com","baz.com"]), "Data stored for sites");
      ok(!stored(["quz.com"]), "Data cleared for quz.com");

      // Clear all data for bar.com.
      pluginHost.clearSiteData(pluginTag, "bar.com", FLAG_CLEAR_ALL, 20);
      ok(stored(["baz.com"]), "Data stored for baz.com");
      ok(!stored(["bar.com"]), "Data cleared for bar.com");

      // Disable clearing by age.
      p.setSitesWithDataCapabilities(false);

      // Attempt to clear data by age.
      checkThrows(function() {
        pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 20);
      }, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);

      checkThrows(function() {
        pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20);
      }, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);

      checkThrows(function() {
        pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, 20);
      }, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);

      checkThrows(function() {
        pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, 20);
      }, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);

      // Clear cache for baz.com and globally for all ages.
      pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, -1);
      pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, -1);

      // Check that all of the above were no-ops.
      ok(stored(["baz.com"]), "Data stored for baz.com");

      // Clear everything for baz.com.
      pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, -1);
      ok(!stored(["baz.com"]), "Data cleared for baz.com");
      ok(!stored(null), "All data cleared");

      // Set data to test subdomains, IP literals, and 'localhost'-like hosts.
      p.setSitesWithData(
        "foo.com:0:0," +
        "bar.foo.com:0:0," +
        "baz.foo.com:0:0," +
        "bar.com:0:0," +
        "[192.168.1.1]:0:0," +
        "localhost:0:0"
      );

      ok(stored(["foo.com","nonexistent.foo.com","bar.com","192.168.1.1","localhost"]),
        "Data stored for sites");

      // Clear data for "foo.com" and its subdomains.
      pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_ALL, -1);
      ok(stored(["bar.com","192.168.1.1","localhost"]), "Data stored for sites");
      ok(!stored(["foo.com"]), "Data cleared for foo.com");
      ok(!stored(["bar.foo.com"]), "Data cleared for subdomains of foo.com");

      // Clear data for "bar.com" using a subdomain.
      pluginHost.clearSiteData(pluginTag, "foo.bar.com", FLAG_CLEAR_ALL, -1);
      ok(!stored(["bar.com"]), "Data cleared for bar.com");

      // Clear data for "192.168.1.1".
      pluginHost.clearSiteData(pluginTag, "192.168.1.1", FLAG_CLEAR_ALL, -1);
      ok(!stored(["192.168.1.1"]), "Data cleared for 192.168.1.1");

      // Clear data for "localhost".
      pluginHost.clearSiteData(pluginTag, "localhost", FLAG_CLEAR_ALL, -1);
      ok(!stored(null), "All data cleared");

      // Set data to test international domains.
      p.setSitesWithData(
        "b\u00FCcher.es:0:0," +
        "b\u00FCcher.uk:0:0," +
        "xn--bcher-kva.NZ:0:0"
      );

      // Check that both the ACE and UTF-8 representations register.
      ok(stored(["b\u00FCcher.es","xn--bcher-kva.es","b\u00FCcher.uk","xn--bcher-kva.uk"]),
        "Data stored for sites");

      // Clear data for the UTF-8 version.
      pluginHost.clearSiteData(pluginTag, "b\u00FCcher.es", FLAG_CLEAR_ALL, -1);
      ok(!stored(["b\u00FCcher.es"]), "Data cleared for UTF-8 representation");
      ok(!stored(["xn--bcher-kva.es"]), "Data cleared for ACE representation");

      // Clear data for the ACE version.
      pluginHost.clearSiteData(pluginTag, "xn--bcher-kva.uk", FLAG_CLEAR_ALL, -1);
      ok(!stored(["b\u00FCcher.uk"]), "Data cleared for UTF-8 representation");
      ok(!stored(["xn--bcher-kva.uk"]), "Data cleared for ACE representation");

      // The NPAPI spec requires that the plugin report sites in normalized
      // UTF-8. We do happen to normalize the result anyway, so while that's not
      // strictly required, we test it here.
      ok(stored(["b\u00FCcher.nz","xn--bcher-kva.nz"]),
        "Data stored for sites");
      pluginHost.clearSiteData(pluginTag, "b\u00FCcher.nz", FLAG_CLEAR_ALL, -1);
      ok(!stored(["b\u00FCcher.nz"]), "Data cleared for UTF-8 representation");
      ok(!stored(["xn--bcher-kva.nz"]), "Data cleared for ACE representation");
      ok(!stored(null), "All data cleared");

      SimpleTest.finish();
    }
  </script>
</body>
</html>
